
#import "InfoView.h"

#import <math.h>

#define RANDINT(n) (random() % ((n)+1))		 

inline float restrictValue(float val, float max, float min)
{
	if (val > max)
		return max;
    else if (val < min)
		return min;
    else
		return val;
}

@implementation InfoView

void handler(DPSTimedEntry teNumber, double now, void *userData)
{
	id obj = (id) userData;
	[obj animationClick];
}

- initFrame:(NXRect *)frameRect;
{
   	id bundle;
	char buf[MAXPATHLEN + 1];
	char fileName[MAXPATHLEN + 1];

  	[super initFrame:frameRect];
	bundle = [NXBundle bundleForClass:[self class]];
	if(![bundle getPath:buf 
        forResource:"InfoPanel" 
        ofType:"nib"])
		return nil;
	strcpy(fileName, buf);
	strcat(fileName, "/OutOfTheWood.tiff");	
   	oldImage = frontImage = [[NXImage alloc] initFromFile:fileName];
	strcpy(fileName, buf);
	strcat(fileName, "/Credits.tiff");
	image = [[NXImage alloc] initFromFile:fileName];
	strcpy(fileName, buf);
	strcat(fileName, "/bat.tiff");
   	bat = [[NXImage alloc] initFromFile:fileName];
	strcpy(fileName, buf);
	strcat(fileName, "/BatSound.snd");
   	batSound = [[Sound alloc] initFromSoundfile:fileName];
	toggle = YES;
   	[image getSize:&imageSize];
	[bat getSize:&batSize];
   	buffer = [[NXImage alloc] initSize:&imageSize];  	
	[self compositeWithDissolve:NO andDelta:0.0];
	frontPage = YES;
   	return self;
}
   
- free;
{
	[self removeTe];
   	[image free];
   	[oldImage free];
   	[buffer free];
	[bat free]; 
   	return [super free];
}

- compositeWithDissolve:(BOOL)aBool andDelta:(float)aDelta
{
	NXPoint pt = {0.0,0.0};

   	[buffer lockFocus];
  	[oldImage composite:NX_COPY toPoint:&pt];
   	if(aBool)
   		[image dissolve:aDelta toPoint:&pt];    
   	[buffer unlockFocus];	
   	return self;
}

- compositeWithChecker:(BOOL)aBool andDelta:(float)aDelta
{
    NXRect rects[64], r;
    NXSize imgSize,rectSize;
    NXPoint pt = {0.0,0.0};
    float height,h;
    int x, y, index;
	id img;
    
    [buffer lockFocus];
	[oldImage composite:NX_COPY toPoint:&pt];
	if(!aBool){
		[buffer unlockFocus];
		return self;
	}
    [image getSize:&imgSize];
    img = [[NXImage alloc] initSize:&imgSize];
    rectSize.width = imgSize.width / 8;
    rectSize.height = imgSize.height / 8;
    height = 2 * aDelta * rectSize.height;
    h = height - rectSize.height;
    for(x = 0; x < 8; x ++){
		for(y = 0; y < 8; y ++){
	    	index = x + y * 8;
	    	if(height > rectSize.height){
				if((x % 2) == (y % 2)){
		    		NXSetRect(&rects[index],x * rectSize.width,
		    		(y + 1) * rectSize.height - h,
					rectSize.width, h);
				} else {
		    		NXSetRect(&rects[index],x * rectSize.width,
		    		y * rectSize.height,
					rectSize.width,rectSize.height);
				}
	    	} else {
				if((x % 2) != (y % 2)){
		    		NXSetRect(&rects[index],x * rectSize.width,
		    		y * rectSize.height,rectSize.width, height);
				} else {
		   			NXSetRect(&rects[index],0,0,0,0);
				}
	    	}
		}
    }
    [img lockFocus];
    PSsetgray(0.0);
    PSsetalpha(0.0);
    NXSetRect(&r,0,0,imgSize.width,imgSize.height);
    NXRectFill(&r);
    PSsetalpha(1.0);
    NXRectFillList(rects,64);
    [image composite:NX_SIN toPoint:&pt];
    [img unlockFocus];
    [img composite:NX_SOVER toPoint:&pt];
    [buffer unlockFocus];
    [img free];
    return self;
}

- drawSelf:(NXRect *)rects :(int)rectCount;
{
   NXPoint p1 = {0.0, 0.0};
	
   PSsetgray (NX_LTGRAY);
   NXRectFill (&bounds);
   [buffer composite:NX_COPY toPoint:&p1];
   return self;
}

- mouseDown:(NXEvent *) thisEvent
{
   	delta = 0.0;		
   	[self compositeWithDissolve:NO andDelta:delta];
    [self display];
	animationDissolve =YES;
	animationCrowl = NO;
	animationStep = 0; 
	if(!animateTe)
		animateTe = DPSAddTimedEntry(.03,(DPSTimedEntryProc) handler, self, NX_BASETHRESHOLD);   
    return self;
}

- start:sender
{
	[self display];
	[self removeTe];
	animationDissolve = NO;
	animationCrowl = YES;
	animationStep = 0;
	randDirection = 0;
	batRect.origin.y = 50.0;
	batRect.origin.x = 50.0;
	batRect.size.width = batSize.width;
	batRect.size.height = batSize.height / 4;
	if(!animateTe)
		animateTe = DPSAddTimedEntry(.03,(DPSTimedEntryProc) handler, self, NX_BASETHRESHOLD);	
	return self;
}

- stop:sender
{
	[self removeTe];
	return self;
}

- animationClick
{
	if(animationCrowl)
		[self animateCrowl];
	if(animationDissolve)
		[self animateDissolve];
	NXPing();
	return self;
}

- animateCrowl
{
	NXRect tmpRect;
	int nr;

	[self lockFocus];
		[self drawBackground:&batRect];
		if(animationStep % 11 == 0)
			randDirection = RANDINT(7);
		if(animationStep % 13 == 0 && randDirection % 2 == 0)
			[batSound play:self];
		switch(randDirection){
			case 0 :batRect.origin.x += 1;
					break;
			case 1 :batRect.origin.x += 1;
					batRect.origin.y += 1;
					break;
			case 2 :batRect.origin.y += 1;
					break;
			case 3 :batRect.origin.x -= 1;
					batRect.origin.y += 1;
					break;
			case 4 :batRect.origin.x -= 1;
					break;
			case 5 :batRect.origin.x -= 1;
					batRect.origin.y -= 1;
					break;
			case 6 :batRect.origin.y -= 1;
					break;
			case 7 :batRect.origin.x += 1;
					batRect.origin.y -= 1;
					break;
		}	
		animationStep++;
		batRect.origin.x = restrictValue(batRect.origin.x,200,50);
		batRect.origin.y = restrictValue(batRect.origin.y,230,50);
		NXSetRect(&tmpRect,0,0,batSize.width,batSize.height / 4);
		nr = animationStep % 8;
		switch(nr){
			case 1:
			case 6:
					tmpRect.origin.y += batSize.height / 4;
					break;
			case 2:
			case 5:
					tmpRect.origin.y += batSize.height / 2;
					break;
			case 3:
			case 4:
					tmpRect.origin.y += 3 * batSize.height / 4;
					break;
		}
		[bat composite:NX_SOVER fromRect:&tmpRect toPoint:&batRect.origin];
		[[self window] flushWindow];
	[self unlockFocus];
	return self;
}

- animateDissolve
{
	id dummy;

	delta = delta + 0.20;
	if(toggle)
		[self compositeWithDissolve:YES andDelta:delta];
	else
		[self compositeWithChecker:YES andDelta:delta];
	[self display];
	if(delta < 1.0)
		return self;
	toggle = !toggle;
	dummy = oldImage;
    oldImage = image;
    image = dummy;
	frontPage = (!frontPage);
	[self removeTe];
	if(frontPage)
		[self start:self];
	return self;
}

- removeTe
{
	if(animateTe){
		DPSRemoveTimedEntry(animateTe);
		animateTe = 0;
	}
	return self;
}

- drawBackground:(NXRect *)rect
{
    NXRect tmpRect = *rect;

    NX_X(&tmpRect) = floor(NX_X(&tmpRect));
    NX_Y(&tmpRect) = floor(NX_Y(&tmpRect));
    if (NXDrawingStatus == NX_DRAWING) {
		PSsetgray (NX_WHITE);
		PScompositerect (NX_X(&tmpRect), NX_Y(&tmpRect),
			 			 NX_WIDTH(&tmpRect), NX_HEIGHT(&tmpRect), NX_SOVER);
    }
    [frontImage composite:NX_SOVER fromRect:&tmpRect toPoint:&tmpRect.origin];
    return self;
}

- windowWillClose:sender
{
	id dummy;
	
	[self stop:self];
	if(!frontPage){
		toggle = !toggle;
		frontPage = YES;
		dummy = oldImage;
    	oldImage = image;
    	image = dummy;
		[self compositeWithDissolve:NO andDelta:0.0];
	}
	return self;
}

- woodPage:sender
{
	Pasteboard *pboard = nil;
	static const char *url = NULL;
	const char *types[1];
	
	if(!url){
		if(strings)
			url = [strings valueForStringKey:"URL"];
		else
			url= NXUniqueString("file:/Hoffmann/Uwe/Library/HTML/HomePage/Wood/Wood.html");
	}
	if(!pboard)
		pboard = [Pasteboard newUnique];
	types[0] = NXAsciiPboardType;
	[pboard declareTypes:types num:1 owner:NXApp];
	[pboard writeType:NXAsciiPboardType 
		data:url length:strlen(url)];
	if(NXPerformService("OmniWeb/Open URL", pboard))
		[window performClose:self];
	else if(NXPerformService("SpiderWoman/Open URL", pboard))
		[window performClose:self];
	else if(NXPerformService("NetSurfer/Open URL", pboard))
		[window performClose:self];
	else
		NXBeep();
	return self;
}

@end
